/*
 * Created by SharpDevelop.
 * User: David
 * Date: 2006-12-05
 * Time: 21:30
 * 
 * To change this template use Tools | Options | Coding | Edit Standard Headers.
 */

using System;
using System.Collections.Generic;
using System.Windows.Forms;

using tools;

using Labb4.Main;
using Labb4.Pooman.Game;

namespace Labb4.Event
{
	/// <summary>
	/// Handles the events. This is where you play events, or triggers them so to speak.
	/// 
	/// Implements the Singleton design pattern
	/// </summary>
	public sealed class EventHandler : Manager
	{
		#region members
		
		/// <summary>
		/// The one instance of this class
		/// </summary>
		private static EventHandler		m_Instance = new EventHandler();
		
		/// <summary>
		/// The events in this queue are played one after a nother with a short interval set
		/// by event distance members
		/// </summary>
		private List<Event>				m_TimedEventQueue;
		/// <summary>
		/// The events in this queue are played one by one, one after the other
		/// </summary>
		private List<Event>				m_EventQueue;
		/// <summary>
		/// Events in this queue are played emidiately
		/// </summary>
		private List<Event>				m_ImmediateEvents;
		
		/// <summary>
		/// The minimum time passed between events started in the TimedEventQueue. Unit is (ms)
		/// </summary>
		private int						m_MinEventDistance;
		/// <summary>
		/// The maximum time passed between events started in the TimedEventQueue. Unit is (ms)
		/// </summary>
		private int						m_MaxEventDistance;
		/// <summary>
		/// This is the time that the next event should be started. Unit it (ms)
		/// </summary>
		private int						m_NextEvent;
		/// <summary>
		/// This is the current time in the EventHandler
		/// </summary>
		private int						m_Counter;
		
		#endregion
		
		#region constructors
		
		/// <summary>
		/// Constructor, initializes members
		/// </summary>
		private EventHandler() :
			base()
		{
			m_TimedEventQueue = new List<Event>();
			m_EventQueue = new List<Event>();
			m_ImmediateEvents = new List<Event>();
			
			m_MinEventDistance = 0;
			m_MaxEventDistance = 0;
			m_NextEvent = 0;
			m_Counter = 0;
		}
		
		#endregion
		
		#region methods
		
		/// <summary>
		/// Adds an event to the timed queue, meaning it will start emidiately if this queue is empty, but
		/// wait for its turn if the queue is not empty.
		/// 
		/// <see cref="this.TimedEventQueue">See the field TimedEventQueue</see>
		/// </summary>
		/// <param name="e">The event to add</param>
		public void AddEventToTimedQueue(Event e)
		{
			m_TimedEventQueue.Add(e);
		}
		
		/// <summary>
		/// Adds an event to the queue, meaning it will start emidiately if this queue is empty, but
		/// wait for its turn if the queue is not empty.
		/// 
		/// <see cref="this.EventQueue">See the field EventQueue</see>
		/// </summary>
		/// <param name="e">The event to add</param>
		public void AddEventToQueue(Event e)
		{
			m_EventQueue.Add(e);
			
			if(m_EventQueue.Count < 2)
			{
				e.PlayEvent();
			}
		}
		
		/// <summary>
		/// Adds an event to the emidiate queue, meaning it's guaranteed to start emidiately
		/// </summary>
		/// <param name="e"></param>
		public void AddEventAndPlay(Event e)
		{
			m_ImmediateEvents.Add(e);
		}
		
		/// <summary>
		/// Checks if the event is in queue.
		/// </summary>
		/// <param name="e">The event to look for</param>
		/// <returns>True if the event is in one of the queues, otherwise false</returns>
		public bool EventIsInQueue(Event e)
		{
			return m_TimedEventQueue.Contains(e) | m_EventQueue.Contains(e) | m_ImmediateEvents.Contains(e);
		}
		
		/// <summary>
		/// Empties all the queues
		/// </summary>
		public void Clear()
		{
			m_TimedEventQueue.Clear();
			m_EventQueue.Clear();
			m_ImmediateEvents.Clear();
			
			m_NextEvent = 0;
		}
		
		#endregion
		
		#region overrides
		
		/// <summary>
		/// Initialize routine, sets the minimum and maximum event distance
		/// </summary>
		protected override void DoInitialize()
		{
			Config config = new Config();
			config.Open(Properties.Instance.StartPath + "resources\\configfiles\\eventhandler.txt");
			
			MainForm.ErrorCheck(config.GetInt("min_event_distance", ref m_MinEventDistance));
			MainForm.ErrorCheck(config.GetInt("max_event_distance", ref m_MaxEventDistance));
		}
		
		/// <summary>
		/// Updates the event queues, starts events if they're supposed to, depending on what queue they're in
		/// </summary>
		/// <param name="deltaTime">Time passed since last call to update. Unit is (ms)</param>
		protected override void DoUpdate(ref int deltaTime)
		{
			m_Counter += deltaTime;
			
			if(m_Counter > m_NextEvent)
			{
				TriggerNextEvent();
			}
			
			if(m_ImmediateEvents.Count > 0)
			{
				foreach(Event it in m_ImmediateEvents)
				{
					it.PlayEvent();
				}
				
				m_ImmediateEvents.Clear();
			}
			
			if(m_EventQueue.Count > 0)
			{
				if(!m_EventQueue[0].Playing)
				{
					m_EventQueue.RemoveAt(0);
					
					if(m_EventQueue.Count > 0)
					{
						m_EventQueue[0].PlayEvent();
					}
				}
			}
		}
		
		#endregion
		
		#region properties
		
		/// <summary>
		/// The one instance (get)
		/// </summary>
		public static EventHandler Instance
		{
			get
			{
				return m_Instance;
			}
		}
		
		#endregion
		
		#region private methods
		
		/// <summary>
		/// Starts the next event on the TimedEventQueue.
		/// </summary>
		private void TriggerNextEvent()
		{
			if(m_TimedEventQueue.Count > 0)
			{
				Event nextEvent = m_TimedEventQueue[0];
				m_TimedEventQueue.RemoveAt(0);
				m_NextEvent = m_Counter + Randomizer.Instance.Next(m_MinEventDistance, m_MaxEventDistance);
				
				nextEvent.PlayEvent();
			}
		}
		
		#endregion
	}
}
